<!-- 	Copyright(c) 2020 lutianming www.supersheeps.cn email：641471957@qq.com -->
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>SuperSheeps压测系统测试报告</title>
  <script src="jquery.min.js"></script>
  <script src="echarts.min.js"></script>
    <style>a{text-decoration:none}</style>
</head>
<body bgcolor="#E1FFFF">
    <header><h2>SuperSheeps压测系统测试报告</h2></header>
    <content>
        <table width="100%">
            <tr bgcolor="#FFA07A"><td><bhead hidden><!--bhead--></bhead></td></tr>
            <tr bgcolor="#87CEEB"><td><table hidden><!--list--></table></td></tr>
            <tr><td><div><suboption></suboption><div id="subdetail"><!--detail--></div></div></td></tr>
        </table>
    </content>
</body>
<script>
$(document).ready(show_task_report_info);

function timestampToTime(timestamp) {
  var date = new Date(timestamp);
  var Y = date.getFullYear() + '-';
  var M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1) + '-';
  var D = (date.getDate() < 10 ? '0'+date.getDate() : date.getDate()) + ' ';
  var h = (date.getHours() < 10 ? '0'+date.getHours() : date.getHours()) + ':';
  var m = (date.getMinutes() < 10 ? '0'+date.getMinutes() : date.getMinutes()) + ':';
  var s = (date.getSeconds() < 10 ? '0'+date.getSeconds() : date.getSeconds());
  strDate = Y+M+D+h+m+s;
  return strDate;
}

var report_data = report_sorce_data

var online_chart = null
var online_option = null

var connect_chart = null
var connect_option = null

var net_chart = null
var net_option = null

var custom_chart = null
var custom_option = null

var api_sort_index = null
var api_sort_ascending = true

var case_time_length = 0

var result_data = {}
var result_right = 0
var run_time_max = 0
var run_time_min = 0
var run_time_avg = 0

function show_task_report_info(){
    var task_info = report_data.task_info
    var task_des = task_info.project_name + ":" + task_info.des
    var loop_mode = task_info.loop_mode
  $("#subdetail").html('<table width=100%>\
    <tr><td colspan=3><b>#'+task_info.task_id+':'+task_des+'</b></td></tr>\
    <tr><td colspan=3>&nbsp&nbsp&nbsp&nbsp总人数:'+task_info.total_user+'&nbsp&nbsp&nbsp&nbsp单次:'+task_info.once_user+'&nbsp&nbsp&nbsp&nbsp间隔:'+task_info.space_time+
        '&nbsp&nbsp&nbsp&nbsp循环:'+(loop_mode == 1 ?"否":loop_mode==0?"是":"实时回放")+'</td></tr>\
    <tr><td colspan=3>&nbsp&nbsp&nbsp&nbsp<a id="report_case_info">用例步骤数:0&nbsp&nbsp&nbsp&nbsp用例时长:0时0分0秒</a>&nbsp&nbsp&nbsp&nbsp<a id="report_run_time_info">执行效率：</a>\
      <br>&nbsp&nbsp&nbsp&nbsp<a id="report_user_done_info">预计最大在线:0&nbsp&nbsp&nbsp&nbsp完成人数:0&nbsp;&nbsp;&nbsp;&nbsp;成功:0&nbsp&nbsp&nbsp&nbsp失败:0</a><br><br></td></tr>\
    <tr><td colspan=3><div id="online_chart" style="width:100%;height:250px;"></div></td></tr>\
    <tr><td colspan=3><div id="connect_chart" style="width:100%;height:250px;"></div></tr>\
    <tr><td colspan=3><div id="net_chart" style="width:100%;height:250px;"></div></tr>\
    <tr><td colspan=3><div id="custom_chart" style="width:100%;height:250px;"></div></td></tr>\
    <tr><td colspan=3><h3>&nbsp;接口统计</h3><div style="width:95%;margin-left:2%;overflow-y:scroll"><font size="1">(*点击表头排序)</font><table id="api_head" style="width:100%;table-layout:fixed"><thead>\
    <tr bgcolor="#aeeeee"><td rowspan=2 width=250>名称</td><td colspan=3>发送</td><td colspan=5>接收</td><td colspan=11>耗时(毫秒,百分位)</td></tr>\
    <tr bgcolor="#aeeeee"><td>次数(s)</td><td>流量(s)</td><td>平均(s)</td><td>次数(r)</td><td>流量(r)</td><td>平均(r)</td><td>正确</td><td>错误</td>\
    <td>10%</td><td>20%</td><td>30%</td><td>40%</td><td>50%</td><td>60%</td><td>70%</td><td>80%</td><td>90%</td><td>最小</td><td>最大</td></tr></thead></table></div>\
    <div style="width:95%;min-height:200px;max-height:800px;margin-left:2%;overflow-y:scroll"><table id="api_chart" style="width:100%;table-layout:fixed"></table></div></td></tr>\
    <tr><td colspan=3><h3>&nbsp;结果统计</h3><div style="width:95%;margin-left:2%"><table id="result_chart" width=100%></table></div>\
    <br><br><textarea id="error_chart" disabled rows="30" style="width:100%"></textarea></td></tr>\
    </table>');

  if (online_option == null){
    online_option = {title:{text:'人数统计'},grid:{left:'5%',right:'5%'},legend: {left:'10%',top:'0%'},dataZoom:[{type:"inside"}],tooltip:{trigger:'axis'},
    xAxis:{type:'category',boundaryGap:false,data:[]},yAxis: {nameTextStyle:{align:"left"},name: "单位:人"},
      series:[ {name:'总人数',type:'line',data:[]},{name:'启动',type:'line',data:[]},{name:'存活',type:'line',data:[]},
      {name:'在线',type:'line',data:[]},{name:'成功',type:'line',data:[]},{name:'错误',type:'line',data:[]}]
    }
  };
  online_chart = echarts.init(document.getElementById('online_chart'));
  online_chart.setOption(online_option);

  if (connect_option == null){
    connect_option = {title:{text:'连接统计'},grid:{left:'5%',right:'5%'},legend: {left:'10%',top:'0%'},dataZoom:[{type:"inside"}],tooltip:{trigger:'axis'},
    xAxis:{type:'category',boundaryGap:false},yAxis: {nameTextStyle:{align:"left"},name: "单位:个"},
      series:[]
    }
  };
  connect_chart = echarts.init(document.getElementById('connect_chart'));
  connect_chart.setOption(connect_option);

  if (net_option == null){
    net_option = {title:{text:'流量统计'},grid:{left:'5%',right:'5%'},legend: {left:'10%',top:'0%'},dataZoom:[{type:"inside"}],tooltip:{trigger:'axis', formatter:show_report_net_flow_formater},
    xAxis:{type:'category',boundaryGap:false},
    yAxis: {nameTextStyle:{align:"left"},name: "单位:字节/5秒  (*仅统计应用层流量，带宽数据为理论计算值)"},
      series:[]
    }
  };
  net_chart = echarts.init(document.getElementById('net_chart'));
  net_chart.setOption(net_option);

  if (custom_option == null){
    custom_option = {title:{text:'数量统计'},grid:{left:'5%',right:'5%'},legend: {left:'10%',top:'0%'},dataZoom:[{type:"inside"}],tooltip:{trigger:'axis'},xAxis:{type:'category',boundaryGap:false,data:[]},
    yAxis: {nameTextStyle:{align:"left"},name:"单位:无  (*自定义数量统计)"},
      series:[]
    }
  };
  custom_chart = echarts.init(document.getElementById('custom_chart'));
  custom_chart.setOption(custom_option);

  window.addEventListener("resize",function(){online_chart.resize();});
  window.addEventListener("resize",function(){connect_chart.resize();});
  window.addEventListener("resize",function(){net_chart.resize();});
  window.addEventListener("resize",function(){custom_chart.resize();});

  show_report_api_sort_select()
  show_report_chart_info()
}

function show_report_net_flow_formater(parms){
  var len = parms.length
  var timestamp = ""
  var content = ""
  for (var i = 0;i<len;i++){
    item = parms[i]
    if (i == 0){
      timestamp = item.axisValue
    }
    var flow = Number(item.value[1])
    var Mb = (flow / (1024*1024)).toFixed(3)
    var Mbps = ((Number(item.value[2]) * 8) / (1024*1024*5)).toFixed(3)
    content += item.marker + item.seriesName + " " + item.value[1] + "字节(≈"+Mb+"Mb, 带宽：≈"+Mbps+"Mbps)"+ "<br>"
  }
  return timestamp + "<br>" + content
}

function show_report_chart_info(){
    var content = report_data.report_info
    case_time_length = content.case_time_len
    if (case_time_length == 0) case_time_length = 1
    var sec = case_time_length%60
    var min = Math.floor(case_time_length/60)
    var hou = Math.floor(min/60)
    min = min%60
    var info = '用例步骤:'+ content.case_step_len +'&nbsp&nbsp&nbsp&nbsp用例时长:'+hou+'时'+min+'分'+sec+'秒'
    $("#report_case_info").html(info)
    info = '预计最大在线人数:'+content.max_online+'&nbsp&nbsp&nbsp&nbsp完成人数:'+(content.run_success+content.run_failed) 
        +'&nbsp&nbsp&nbsp&nbsp成功:'+content.run_success+'&nbsp&nbsp&nbsp&nbsp失败:'+content.run_failed
    $("#report_user_done_info").html(info)
    show_report_online_chart_data();
    show_report_connect_chart_data();
    show_report_net_chart_data();
    show_report_custom_chart_data();
    show_report_error_chart_data();
    show_report_api_chart_data_content(report_data.api)

    $("suboption").html('<a id="report_download" href="javascript:void(null);">导出源数据</a>')
    $("#report_download").click(show_report_download_chat_data)
}

function show_report_online_chart_data(){
    var data = report_data.online
    for (i = 0 ,len = data.length;i<len;i++){
        item = data[i].split('|');
        x = timestampToTime(Number(item[0])*1000)
        online_option.xAxis.data.push(x)
        online_option.series[0].data.push(Number(item[1]))
        online_option.series[1].data.push(Number(item[2]))
        online_option.series[2].data.push(Number(item[3]))
        online_option.series[3].data.push(Number(item[4]))
        online_option.series[4].data.push(Number(item[5]))
        online_option.series[5].data.push(Number(item[6]))
    }
    online_chart.setOption(online_option);
}

function show_report_connect_chart_data(){
    var data = report_data.connect
    for (i = 0 ,len = data.length;i<len;i++){
        item = data[i].split('|');
        x = timestampToTime(Number(item[0])*1000)

        var exist = false
        for (j = 0, n = connect_option.series.length; j < n; j++){
          if (connect_option.series[j].key == item[1]){
            connect_option.series[j].data.push([x, item[2]]);
            connect_option.series[j+1].data.push([x, item[3]]);
            exist = true;
            break;
          }
        }
        if (exist == false){
          connect_option.series.push({key:item[1], name: item[1]+'成功', type:"line", data:[[x, item[2]]]})
          connect_option.series.push({key:item[1], name: item[1]+'失败', type:"line", data:[[x, item[3]]]})
        }
    }
    connect_chart.setOption(connect_option);
}

function show_report_net_chart_data(){
    var data = report_data.net
    for (i = 0 ,len = data.length;i<len;i++){
        item = data[i].split('|');
        x = timestampToTime(Number(item[0])*1000)

        var exist = false
        for (j = 0, n = net_option.series.length; j < n; j++){
          if (net_option.series[j].key == item[1]){
            net_option.series[j].data.push([x, item[2], item[4]]);
            net_option.series[j+1].data.push([x, item[3], item[5]]);
            exist = true;
            break;
          }
        }
        if (exist == false){
          x0 = timestampToTime((Number(item[0]) - 5)*1000)
          net_option.series.push({key:item[1], name: item[1]+'上传', type:"line", data:[[x0, 0],[x, item[2], item[4]]]})
          net_option.series.push({key:item[1], name: item[1]+'下载', type:"line", data:[[x0, 0],[x, item[3], item[5]]]})
        }
    }
    net_chart.setOption(net_option);
}

function show_report_custom_chart_data(){
    var data = report_data.custome
    var custom_xmax = 0
    for (i = 0 ,len = data.length;i<len;i++){
        item = data[i].split('|');
        var timestamp = Number(item[0])
        if (custom_xmax == 0){
          custom_xmax = timestamp
          custom_option.xAxis.data.push(timestampToTime(timestamp*1000))
        }
        if (timestamp > custom_xmax){
          for (t = custom_xmax + 1; t <= timestamp; t++){
            custom_option.xAxis.data.push(timestampToTime(t*1000))
          }
          custom_xmax = timestamp
        }

        x = timestampToTime(timestamp*1000)
        var exist = false
        for (j = 0, n = custom_option.series.length; j < n; j++){
          if (custom_option.series[j].key == item[1]){
            custom_option.series[j].data.push([x, item[2]]);
            exist = true;
            break;
          }
        }
        if (exist == false){
          custom_option.series.push({key:item[1], name: item[1], type:"line", data:[[x, item[2]]]})
        }
    }
    custom_chart.setOption(custom_option);
}

function show_report_error_chart_data(){
    var data = report_data.error
    var temptext = ""
    for (i = 0 ,len = data.length;i<len;i++){
        item = data[i].split('|');
        item[0] = timestampToTime(Number(item[0])*1000)
        temptext = temptext + item.toString() + "\n"
        //set result_chart
        reason = item[6]
        if (reason == "结束原因:"){
          result_right = result_right + 1
          var run_time_length = item[4].replace("运行时长:", "").replace("秒", "")
          if (run_time_length == 0) run_time_length = 1
          if (run_time_length > run_time_max) { run_time_max = run_time_length }
          if (run_time_length < run_time_min || run_time_min == 0 ){ run_time_min = run_time_length }
          run_time_avg = (run_time_length - run_time_avg) / result_right + run_time_avg
        }
        else{
          reason = reason.replace("结束原因:", "")
          if (result_data[reason] == null){
            result_data[reason] = 1
          }
          else{
            result_data[reason] = result_data[reason] + 1
          }
        }
    }
    $("#error_chart").append(temptext)
    var max = (run_time_max / case_time_length).toFixed(2)
    var min = (run_time_min / case_time_length).toFixed(2)
    var avg = (run_time_avg / case_time_length).toFixed(2)
    $("#report_run_time_info").html("执行效率：最大["+max+"]&nbsp&nbsp最小["+min+"]&nbsp&nbsp平均["+avg+"]")
    var result_str = '<tr bgcolor=\"#aeeeee\"><td width=500>正确</td><td>'+result_right+'</td></tr>'
    var i = 0
    for (var err_str in result_data){
        var touming = 1
        if ((i % 2) != 0){
          touming = 0.7
        }
        i = i + 1
        result_str += '<tr style="background-color:rgba(96, 205, 205, '+ touming +')"><td width=500>'+ err_str+'</td><td>'+result_data[err_str]+'</td></tr>'
    }
    $("#result_chart").html(result_str)
}

function show_report_api_sort_select(){
  $("#api_head td").click(function () {
    var name = $(this).text()
    if (name == api_sort_index){
      api_sort_ascending = api_sort_ascending ? false : true
    } 
    else if(name != "耗时(毫秒,百分位)" && name != "发送" && name != "接收"){
      api_sort_index = name
      api_sort_ascending = false
    }
    show_report_api_chart_data_content(report_data.api)
  });
}

function show_report_api_chart_data_sort(data){
  if (api_sort_index == "名称"){data.sort(function(a, b){return api_sort_ascending? b.api.localeCompare(a.api) : a.api.localeCompare(b.api)})}
  else if (api_sort_index == "次数(s)"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a.send_count, b.send_count)})}
  else if (api_sort_index == "流量(s)"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a.send_flow, b.send_flow)})}
  else if (api_sort_index == "平均(s)"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a.send_count?a.send_flow/a.send_count:null, b.send_count?b.send_flow/b.send_count:null)})}
  else if (api_sort_index == "次数(r)"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a.recv_count, b.recv_count)})}
  else if (api_sort_index == "流量(r)"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a.recv_flow, b.recv_flow)})}
  else if (api_sort_index == "平均(r)"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a.recv_count?a.recv_flow/a.recv_count:null, b.recv_count?b.recv_flow/b.recv_count:null)})}
  else if (api_sort_index == "正确"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a.success, b.success)})}
  else if (api_sort_index == "错误"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a.error, b.error)})}
  else if (api_sort_index == "最小"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a.min, b.min)})}
  else if (api_sort_index == "最大"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a.max, b.max)})}
  else if (api_sort_index == "10%"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a["10"], b["10"])})}
  else if (api_sort_index == "20%"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a["20"], b["20"])})}
  else if (api_sort_index == "30%"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a["30"], b["30"])})}
  else if (api_sort_index == "40%"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a["40"], b["40"])})}
  else if (api_sort_index == "50%"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a["50"], b["50"])})}
  else if (api_sort_index == "60%"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a["60"], b["60"])})}
  else if (api_sort_index == "70%"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a["70"], b["70"])})}
  else if (api_sort_index == "80%"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a["80"], b["80"])})}
  else if (api_sort_index == "90%"){data.sort(function(a, b){return show_report_api_chart_data_sort_value(a["90"], b["90"])})}
}

function show_report_api_chart_data_sort_value(a, b){
    if (a == null && b == null) return 0
    else if(a == null && b != null){return 1}
    else if(a != null && b == null){return -1}
    else{ return api_sort_ascending? a - b : b - a}
}

function flow_format(value){
  var fixstr = ["B","K","M","G","T"]
  var i = 0
  while(true){
    if (value < 1024){break}
    value = value/1024
    i++
  }
  return value.toFixed(i>2?2:0) + fixstr[i]
}

function show_report_api_chart_data_content(data){
  show_report_api_chart_data_sort(data)
  var temptext = ""
  for (i = 0 ,len = data.length;i<len;i++){
    var item = data[i]
    var touming = 1
    if ((i % 2) != 0){
      touming = 0.7
    }
    item_send_flow = item.send_flow != null?flow_format(item.send_flow) : "-"
    item_send_count = item.send_count != null?item.send_count : "-"
    item_send_avg_title = item.send_count == null ? null: (item.send_flow/item.send_count).toFixed(0)
    item_send_avg = item_send_avg_title == null ? "-" : flow_format(Number(item_send_avg_title))
    item_recv_flow = item.recv_flow != null?flow_format(item.recv_flow) : "-"
    item_recv_count = item.recv_count != null?item.recv_count : "-"
    item_recv_avg_title = item.recv_count== null?null:(item.recv_flow/item.recv_count).toFixed(0)
    item_recv_avg = item_recv_avg_title== null?"-":flow_format(Number(item_recv_avg_title))
    item_success = item.success != null?item.success:"-"
    item_error = item.error != null?item.error:"-"
    item_min = item.min != null?item.min : "-"
    item_max = item.max != null?item.max : "-"
    item_10 = item["10"]!= null?item ["10"]:"-"
    item_20 = item["20"]!= null?item ["20"]:"-"
    item_30 = item["30"]!= null?item ["30"]:"-"
    item_40 = item["40"]!= null?item ["40"]:"-"
    item_50 = item["50"]!= null?item ["50"]:"-"
    item_60 = item["60"]!= null?item ["60"]:"-"
    item_70 = item["70"]!= null?item ["70"]:"-"
    item_80 = item["80"]!= null?item ["80"]:"-"
    item_90 = item["90"]!= null?item ["90"]:"-"
    rowtext = '<tr><td width=250 title="'+item.api+'" style="background-color:rgba(96, 205, 205, '+ touming +');overflow:hidden;text-overflow:ellipsis;">'+item.api+'</td>\
    <td style="background-color:rgba(188, 210, 238, '+ touming +')">'+item_send_count+'</td>\
    <td style="background-color:rgba(188, 210, 238, '+ touming +')"'+ (item.send_flow?' title="'+item.send_flow+'字节"':"")+'>'+item_send_flow+'</td>\
    <td style="background-color:rgba(188, 210, 238, '+ touming +')"'+ (item_send_avg_title?' title="'+item_send_avg_title+'字节"':"")+'>'+item_send_avg+'</td>\
    <td style="background-color:rgba(188, 210, 238, '+ touming +')">'+item_recv_count+'</td>\
    <td style="background-color:rgba(188, 210, 238, '+ touming +')"'+ (item.recv_flow?' title="'+item.recv_flow+'字节"':"")+'>'+item_recv_flow+'</td>\
    <td style="background-color:rgba(188, 210, 238, '+ touming +')"'+ (item_recv_avg_title?' title="'+item_recv_avg_title+'字节"':"")+'>'+item_recv_avg+'</td>\
    <td style="background-color:rgba(188, 210, 238, '+ touming +')">'+item_success+'</td><td style="background-color:rgba(188, 210, 238, '+ touming +')">'+item_error+'</td>\
    <td style="background-color:rgba(178, 223, 238, '+ touming +')">'+item_10+'</td><td style="background-color:rgba(178, 223, 238, '+ touming +')">'+item_20+'</td>\
    <td style="background-color:rgba(178, 223, 238, '+ touming +')">'+item_30+'</td><td style="background-color:rgba(178, 223, 238, '+ touming +')">'+item_40+'</td>\
    <td style="background-color:rgba(178, 223, 238, '+ touming +')">'+item_50+'</td><td style="background-color:rgba(178, 223, 238, '+ touming +')">'+item_60+'</td>\
    <td style="background-color:rgba(178, 223, 238, '+ touming +')">'+item_70+'</td><td style="background-color:rgba(178, 223, 238, '+ touming +')">'+item_80+'</td>\
    <td style="background-color:rgba(255, 180, 180, '+ touming +')">'+item_90+'</td><td style="background-color:rgba(242, 223, 238, '+ touming +')">'+item_min+'</td>\
    <td style="background-color:rgba(242, 223, 238, '+ touming +')">'+item_max+'</td>\</tr>'
    temptext = temptext + rowtext
  }
  $("#api_chart").html(temptext)
}

function show_report_download_chat_data(){
    var task = report_data.task_info
    var report_info = report_data.report_info
    var file_name = timestampToTime(report_info.start_time*1000) + "_"+ task.project_name + "_" + task.des
    file_name = file_name.replace(" ", "_")
    var alink = document.createElement('a')
    alink.href = "data:text/plain;charset=utf-8," + encodeURIComponent(JSON.stringify(report_data, null, '\t'))
    alink.download = file_name+".txt"
    alink.click()
}
</script>
</html>
